/*
Демонстрируется Клавиатура 4x4

CodeVisionAVR C Compiler
(C) 2000-2002 HP InfoTech S.R.L.
www.hpinfotech.ro

Чип: AT90S8515
Подсоедините матричную клавиатуру следующим образом:

[РАЗЪЕМ PORTD STK500] [КНОПКИ] R1
1 PD0 -----0----1----2----3----~~~~~---o+5V
           |    |    |    |    R2    |
2 PD1 -----4----5----6----7----~~~~~-
           |    |    |    |    R3    |
3 PD2 -----8----9----10---11---~~~~~-
           |    |    |    |    R4    |
4 PD3 -----12---13---14---15---~~~~~-
       D1  |    |    |    |
5 PD4 -|<|-     |    |    |
       D2       |    |    |
6 PD5 -|<|------     |    |
       D3            |    |
7 PD6 -|<|-----------     | R1..R4=10k..47k
       D4                 |
8 PD7 -|<|---------------- D1..D4=1N4148

Используйте цифро-буквенный LCD 2x16, подключенный
к разъему PORTC STK500 следующим образом:

[LCD]   [РАЗЪЕМ PORTC STK500]
1 GND - 9 GND
2 +5V - 10 VCC
3 VLC - управление контрастностью LCD напряжение 0..1V
4 RS  - 1 PC0
5 RD  - 2 PC1
6 EN  - 3 PC2
11 D4 - 5 PC4
12 D5 - 6 PC5
13 D6 - 7 PC6
14 D7 - 8 PC7
*/
#asm
  .equ __lcd_port=0x15
#endasm

#include <lcd.h>
#include <stdio.h>
#include <delay.h>
#include <90s8515.h>

// частота кварца [Гц]
#define F_XTAL 3686400L
// PIND0..3 будут входами рядов
#define KEYIN PIND
// PORTD4..7 будут выходами столбцов
#define KEYOUT PORTD
// используем для инициализации счета Таймера/Счетчика 0
#define INIT_TIMER0 TCNT0=0x100L-F_XTAL/64L/500L
#define FIRST_COLUMN 0x80
#define LAST_COLUMN 0x10

typedef unsigned char byte;

// сохраним здесь состояние каждой кнопки как бит,
// бит 0 будет KEY0, бит 1 KEY1,...
unsigned keys;
// буфер LCD дисплея
char buf[33];

// прерывание по переполнению Таймера/Счетчика 0 каждые 2 мс
interrupt [TIM0_OVF] void timer0_int(void)
{
static byte key_pressed_counter=20;
static byte key_released_counter,column=FIRST_COLUMN;
static unsigned row_data,crt_key;

// заново инициализируем Таймер/Счетчик 0
INIT_TIMER0;
row_data<<=4;

// получим группу 4 кнопок в переменной row_data
row_data|=~KEYIN&0xf;
column>>=1;

if (column==(LAST_COLUMN>>1))
  {
  column=FIRST_COLUMN;
  if (row_data==0) goto new_key;
  if (key_released_counter) --key_released_counter;
  else
  {
    if (--key_pressed_counter==9) crt_key=row_data;
    else
      {
        if (row_data!=crt_key)
          {
            new_key:
            key_pressed_counter=10;
            key_released_counter=0;
            goto end_key;
             };
           if (!key_pressed_counter)
             {
               keys=row_data;
               key_released_counter=20;
             };
         };
     };
     end_key:;
     row_data=0;
   };
// выберем следующий столбец, входы будут 
// с подтягивающими резисторами
KEYOUT=~column;
}

// проверим, была ли нажата кнопка
unsigned inkey(void)
{
  unsigned k;
  if (k=keys) keys=0;
  return k;
}

void init_keypad(void)
{
  DDRD=0xf0;
  INIT_TIMER0;
  TCCR0=3;
  TIMSK=2;
  #asm("sei")
}

main() 
{
  unsigned k;
  init_keypad();
  lcd_init(16);
  lcd_putsf("CVAVR Keypad");
  
  // прочитаем кнопку и отобразим ее код
  while (1)
  {
    lcd_gotoxy(0,1);
    if (k=inkey())
    {
      sprintf(buf,"Key code=%Xh",k);
      lcd_puts(buf);
    }
    else lcd_putsf("NO KEY        ");
    delay_ms(500);
  }
}
